package com.xb.loan.util.binaryConvert.config;


import com.xb.loan.util.binaryConvert.config.annotation.ParseField;
import com.xb.loan.util.binaryConvert.exception.ParseException;
import com.xb.loan.util.binaryConvert.parse.ParseAble;
import com.xb.loan.util.binaryConvert.parse.bool.BoolParser;
import com.xb.loan.util.binaryConvert.parse.list.ListParser;
import com.xb.loan.util.binaryConvert.parse.map.MapParser;
import com.xb.loan.util.binaryConvert.parse.num.*;
import com.xb.loan.util.binaryConvert.parse.num.*;
import com.xb.loan.util.binaryConvert.parse.obj.ObjParser;
import com.xb.loan.util.binaryConvert.parse.str.StringParser;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class ParseConfigManager {

	private static Map<ParseType, ParseAble<?>> parsers = new HashMap<ParseType, ParseAble<?>>() {

		private static final long serialVersionUID = -4068778285835343137L;

		{
			this.put(ParseType.BOOL, new BoolParser());
			this.put(ParseType.BYTE, new ByteParser());
			this.put(ParseType.DOUBLE, new DoubleParser());
			this.put(ParseType.FLOAT, new FloatParser());
			this.put(ParseType.INT, new IntParser());
			this.put(ParseType.LIST, new ListParser());
			this.put(ParseType.LONG, new LongParser());
			this.put(ParseType.MAP, new MapParser());
			this.put(ParseType.STRUCT, new ObjParser());
			this.put(ParseType.SHORT, new ShortParser());
			this.put(ParseType.STR, new StringParser());
		}

	};

	private static Map<String, ParseType> classParsers = new HashMap<String, ParseType>() {

		private static final long serialVersionUID = 8299622637165594329L;

		{
			this.put("int", ParseType.INT);
			this.put("java.lang.Integer", ParseType.INT);

			this.put("boolean", ParseType.BOOL);
			this.put("java.lang.Boolean", ParseType.BOOL);

			this.put("byte", ParseType.BYTE);
			this.put("java.lang.Byte", ParseType.BYTE);

			this.put("double", ParseType.DOUBLE);
			this.put("java.lang.Double", ParseType.DOUBLE);

			this.put("float", ParseType.FLOAT);
			this.put("java.lang.Float", ParseType.FLOAT);

			this.put("java.util.List", ParseType.LIST);

			this.put("long", ParseType.LONG);
			this.put("java.lang.Long", ParseType.LONG);

			this.put("java.util.Map", ParseType.MAP);

			this.put("java.lang.Short", ParseType.SHORT);
			this.put("short", ParseType.SHORT);

			this.put("java.lang.String", ParseType.STR);
		}

	};
	// 对象各字段转换链
	private static Map<Class<?>, ParseConfig[]> objConfigChain = new ConcurrentHashMap<Class<?>, ParseConfig[]>();

	private static Object lock = new Object();

	@SuppressWarnings("unchecked")
	public static ParseAble getParser(ParseType type) {

		return parsers.get(type);
	}

	// 获取class对应的解析类型
	public static ParseType getParseClassType(Class<?> clazz) {

		String name = clazz.getName();

		return getParseClassType(name);

	}

	private static ParseType getParseClassType(String className) {

		ParseType parseType = classParsers.get(className);

		return parseType == null ? ParseType.STRUCT : parseType;
	}

	// 如果对象是list或者map，需要特殊chul
	public static ParseConfig[] getConfigChain(Class<?> clazz)
			throws ParseException {

		ParseConfig[] configChain = objConfigChain.get(clazz);

		if (configChain == null) {

			synchronized (lock) {

				if (!objConfigChain.containsKey(clazz)) {

					configChain = initClassConfig(clazz);

					objConfigChain.put(clazz, configChain);
				} else {

					configChain = objConfigChain.get(clazz);
				}
			}
		}

		return configChain;
	}

	private static ParseConfig[] initClassConfig(Class<?> clazz)
			throws ParseException {

		List<ParseConfig> configs = new LinkedList<ParseConfig>();

		Set<String> parseFields = new HashSet<String>();

		Set<String> unParseFields = new HashSet<String>();
		// 循环添加父类的方法
		try {
			addInheritClassMethod(clazz, parseFields, unParseFields, configs);
		} catch (Exception e) {
			
			throw new ParseException("initClassConfig have an exception",e);
		}

		if (configs.isEmpty()) {

			throw new ParseException(clazz.getName()
					+ " not have any parse Field!!!");
		}

		// 排序注解的顺序
		return sortConfig(configs);

	}

	private static void addInheritClassMethod(Class<?> clazz,
			Set<String> parseFields, Set<String> unParseFields,
			List<ParseConfig> configs) throws ClassNotFoundException {

		while (clazz != null) {

			Method[] methods = clazz.getDeclaredMethods();

			Field[] fields = clazz.getDeclaredFields();

			for (Field field : fields) {

				int index = 0;
				// 如果是不解析该字段，忽略
				if (field.isAnnotationPresent(ParseField.class)) {

					ParseField parseField = field
							.getAnnotation(ParseField.class);

					if (!parseField.parse()) {

						unParseFields.add(field.getName());
						continue;
					} 
				}
				// 如果是不解析该字段，忽略
				if (unParseFields.contains(field.getName())) {

					continue;
				}

				if (parseFields.add(field.getName())) {
					// 获取get和set方法
					Method getMethod = parseGetMethod(clazz, field, methods);
					// 获取set方法
					Method setMethod = parseSetMethod(clazz, getMethod);

					configs.add(getParseConfig(getMethod, setMethod, index,
							field));
				}
			}

			clazz = clazz.getSuperclass();
		}
	}

	private static ParseConfig getParseConfig(Method getMethod,
			Method setMethod, int index, Field field) throws ClassNotFoundException {
		
		boolean useField = checkUseField(getMethod,setMethod,field);
		
		// list 或者map
		if (field.getType().isInterface()) {

			String typeDefinition = field.getGenericType().toString();
			// list
			if (typeDefinition.matches("java.util.List<.+>")) {

				int listDeep = parseListDeep(typeDefinition);
				Class<?> clazz = parseListValue(typeDefinition);
				
				if(useField){
					
					return new ParseConfig(field,ParseType.LIST,index,listDeep,null,clazz);
				} else{
					
					return new ParseConfig(getMethod,setMethod,ParseType.LIST,index,listDeep,null,clazz);
				}

			} else if (typeDefinition.matches("java.util.Map<[^<>,]+,[^<>,]+>")) {
				
				Class<?> keyClazz = parseMapKey(typeDefinition);
				Class<?> valueClazz = parseMapValue(typeDefinition);
				
				if(useField){
					
					return new ParseConfig(field,ParseType.MAP,index,1,keyClazz,valueClazz);
				} else{
					
					return new ParseConfig(getMethod,setMethod,ParseType.MAP,index,1,keyClazz,valueClazz);
				}
			} else {

				throw new ParseException(typeDefinition
						+ " not recognize this type!!!");
			}

		}

		ParseType parseType = getParseClassType(parseFieldClassName(field));

		if(useField){
			
			return new ParseConfig(field, parseType, index);
		} else{
			
			return new ParseConfig(getMethod, setMethod, parseType, index);
		}
	}

	private static boolean checkUseField(Method getMethod, Method setMethod,
			Field field) {
		// 有get set 方法，使用get/set 方法
		if(getMethod != null && setMethod != null){
			
			return false;
		} 
		// 判断方法是否为public  public 占第一位
		if((field.getModifiers() & 0x0001) == 0x0001){
			
			return true;
		}
		
		throw new ParseException(field.getDeclaringClass().getName()
				+ " not have set or get method,and field type is not public,field is " + field.getName() + "!!!");
		
	}

	private static Class<?> parseMapValue(String typeDefinition) throws ClassNotFoundException {
		
		String valueClass = typeDefinition.substring(typeDefinition.indexOf(',') + 1, typeDefinition.indexOf('>')).trim();
		
		return Class.forName(valueClass);
	}

	private static Class<?> parseMapKey(String typeDefinition) throws ClassNotFoundException {
		
		String keyClass = typeDefinition.substring(typeDefinition.indexOf('<') + 1, typeDefinition.indexOf(',')).trim();
		
		return Class.forName(keyClass);
	}

	private static Class<?> parseListValue(String typeDefinition) throws ClassNotFoundException {
		
		Pattern p = Pattern.compile(".+<([^<>]+)>+");
		
		Matcher matcher = p.matcher(typeDefinition);
		
		matcher.find();
		
		return Class.forName(matcher.group(1));
	}

	private static int parseListDeep(String typeDefinition) {

		int count = 0;

		int index = -1;

		while ((index = typeDefinition.indexOf('<', index + 1)) > 0) {

			count++;
		}

		return count;
	}

	private static String parseFieldClassName(Field field) {

		return field.getType().getName();
	}

	private static Method parseGetMethod(Class<?> clazz, Field field,
			Method[] methods) {

		String tail = selectGetSetMethodTail(field.getName());

		String getName = "get" + tail;

		String isName = "is" + tail;

		for (Method method : methods) {

			if (getName.equals(method.getName())
					|| isName.equals(method.getName())) {
				// 没有参数，则是get方法
				if (method.getParameterTypes().length == 0) {

					return method;
				}
			}
		}
		
		return null;
	}

	// 获取get/set方法的后缀名
	private static String selectGetSetMethodTail(String fileName) {
		// 判断第二个字母是否是大写，如果是大写则为set/get+fileName 否则set/get+第一个字母大写
		if (fileName.length() > 1) {

			char c = fileName.charAt(1);

			if (c != Character.toLowerCase(c)) {

				// 第二个字母是大写，则返回当前名称
				return fileName;
			}
		}
		// 将第一个字母变为大写
		return fileName.substring(0, 1).toUpperCase() + fileName.substring(1);

	}

	private static Method parseSetMethod(Class<?> clazz, Method getMethod)
			throws ParseException {

		if(getMethod == null){
			
			return null;
		}
		
		String methodName = getMethod.getName();

		String setMethodName = null;

		if (methodName.startsWith("get")) {

			setMethodName = methodName.replaceFirst("get", "set");
		} else if (methodName.startsWith("is")) {

			setMethodName = methodName.replaceFirst("is", "set");
		} else {

			return null;
		}

		try {
			Method setMethod = clazz.getDeclaredMethod(setMethodName, getMethod
					.getReturnType());

			return setMethod;

		} catch (Exception e) {

			return null;
		}
	}

	private static ParseConfig[] sortConfig(List<ParseConfig> configs) {

		ParseConfig[] sortConfigs = configs.toArray(new ParseConfig[configs
				.size()]);

		for (int x = 0; x < sortConfigs.length; x++) {

			for (int y = x + 1; y < sortConfigs.length; y++) {

				if (sortConfigs[x].getIndex() > sortConfigs[y].getIndex()) {
					// 互换位置
					ParseConfig temp = sortConfigs[x];
					sortConfigs[x] = sortConfigs[y];
					sortConfigs[y] = temp;
				}
			}
		}

		return sortConfigs;
	}

	public static void main(String[] args) throws ClassNotFoundException {
		
		String str = "java.util.List<<<>";
		
		System.out.println(str.indexOf('<', 15));
		
		System.out.println(parseMapValue("java.util.Map<java.lang.String, java.lang.Integer>"));
	}

}
